﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Windows;
using System.Windows.Data;
using Xceed.Silverlight.Data;
using Xceed.Silverlight.DataGrid.Utils;

namespace Xceed.Silverlight.DataGrid
{
  #region Metadata

  [System.Diagnostics.DebuggerDisplay( "FieldName = {FieldName}" )]
  [StyleTypedProperty( Property = "CellStyle", StyleTargetType = typeof( DataCell ) )]
  [StyleTypedProperty( Property = "ColumnManagerCellStyle", StyleTargetType = typeof( ColumnManagerCell ) )]
  [StyleTypedProperty( Property = "CellEditorStyle", StyleTargetType = typeof( FrameworkElement ) )]

  #endregion Metadata

  public class Column : DependencyObject, INotifyPropertyChanged
  {
    #region Static Fields

    private const double DefaultWidth = 100d;
    private static int NewColumnCount = 0;

    #endregion

    #region Constructors

    public Column()
    {
      this.FieldName = "New Column " + ( ++NewColumnCount );

      m_propertyChangedHelper = new NotifyPropertyChangedHelper( this, this.RaisePropertyChangedEvent );
    }

    public Column( string fieldName )
      : this()
    {
      this.FieldName = fieldName;
    }

    #endregion

    #region ActualWidth Property

    public double ActualWidth
    {
      get
      {
        return m_actualWidth;
      }
      internal set
      {
        if( m_actualWidth == value )
          return;

        m_actualWidth = value;

        this.RaisePropertyChanged( () => this.ActualWidth );
      }
    }

    private double m_actualWidth;

    #endregion //ActualWidth Property

    #region AllowFilter Property

    public static readonly DependencyProperty AllowFilterProperty = DependencyProperty.Register(
      "AllowFilter",
      typeof( bool ),
      typeof( Column ),
      new PropertyMetadata( true, new PropertyChangedCallback( Column.OnAllowFilterChanged ) ) );

    public bool AllowFilter
    {
      get
      {
        return ( bool )this.GetValue( Column.AllowFilterProperty );
      }
      set
      {
        this.SetValue( Column.AllowFilterProperty, value );
      }
    }

    private static void OnAllowFilterChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.AllowFilter );
    }

    #endregion // AllowFilter Property

    #region AllowGroup Property

    public static readonly DependencyProperty AllowGroupProperty = DependencyProperty.Register(
      "AllowGroup",
      typeof( bool? ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnAllowGroupChanged ) ) );

    public bool? AllowGroup
    {
      get
      {
        return ( bool? )this.GetValue( Column.AllowGroupProperty );
      }
      set
      {
        this.SetValue( Column.AllowGroupProperty, value );
      }
    }

    private static void OnAllowGroupChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.AllowGroup );
    }

    #endregion // AllowGroup Property

    #region AllowResize Property

    public static readonly DependencyProperty AllowResizeProperty = DependencyProperty.Register(
      "AllowResize",
      typeof( Nullable<bool> ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnAllowColumnResizeChanged ) ) );

    public Nullable<bool> AllowResize
    {
      get
      {
        return ( Nullable<bool> )this.GetValue( Column.AllowResizeProperty );
      }
      set
      {
        this.SetValue( Column.AllowResizeProperty, value );
      }
    }

    private static void OnAllowColumnResizeChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.AllowResize );
    }

    #endregion

    #region AllowSort Property

    public static readonly DependencyProperty AllowSortProperty = DependencyProperty.Register(
      "AllowSort",
      typeof( Nullable<bool> ),
      typeof( Column ),
      new PropertyMetadata( null ) );

    public Nullable<bool> AllowSort
    {
      get
      {
        return ( Nullable<bool> )this.GetValue( Column.AllowSortProperty );
      }
      set
      {
        this.SetValue( Column.AllowSortProperty, value );
      }
    }

    #endregion // AllowSort Property

    #region CellContentTemplate Property

    public static readonly DependencyProperty CellContentTemplateProperty = DependencyProperty.Register(
      "CellContentTemplate",
      typeof( DataTemplate ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnCellContentTemplateChanged ) ) );

    public DataTemplate CellContentTemplate
    {
      get
      {
        return ( DataTemplate )this.GetValue( Column.CellContentTemplateProperty );
      }
      set
      {
        this.SetValue( Column.CellContentTemplateProperty, value );
      }
    }

    private static void OnCellContentTemplateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellContentTemplate );
    }

    #endregion //CellContentTemplate Property

    #region CellContentStyle Property

    public static readonly DependencyProperty CellContentStyleProperty = DependencyProperty.Register(
      "CellContentStyle",
      typeof( Style ),
      typeof( Column ),
      new PropertyMetadata( null, Column.OnCellContentStyleChanged ) );

    public Style CellContentStyle
    {
      get
      {
        return ( Style )this.GetValue( Column.CellContentStyleProperty );
      }
      set
      {
        this.SetValue( Column.CellContentStyleProperty, value );
      }
    }

    private static void OnCellContentStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellContentStyle );
    }

    #endregion

    #region CellEditorDisplayConditions Property

    public static readonly DependencyProperty CellEditorDisplayConditionsProperty = DependencyProperty.Register(
      "CellEditorDisplayConditions",
      typeof( Nullable<CellEditorDisplayConditions> ),
      typeof( Column ),
      new PropertyMetadata(
        null,
        new PropertyChangedCallback( Column.OnCellEditorDisplayConditionsChanged ) ) );

    public Nullable<CellEditorDisplayConditions> CellEditorDisplayConditions
    {
      get
      {
        return ( Nullable<CellEditorDisplayConditions> )this.GetValue( Column.CellEditorDisplayConditionsProperty );
      }
      set
      {
        this.SetValue( Column.CellEditorDisplayConditionsProperty, value );
      }
    }

    private static void OnCellEditorDisplayConditionsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellEditorDisplayConditions );
    }

    #endregion //CellEditorDisplayConditions Property

    #region EditTriggers Property

    public static readonly DependencyProperty EditTriggersProperty = DependencyProperty.Register(
      "EditTriggers",
      typeof( Nullable<EditTriggers> ),
      typeof( Column ),
      new PropertyMetadata(
        null,
        new PropertyChangedCallback( Column.OnEditTriggersChanged ) ) );

    public Nullable<EditTriggers> EditTriggers
    {
      get
      {
        return ( Nullable<EditTriggers> )this.GetValue( Column.EditTriggersProperty );
      }
      set
      {
        this.SetValue( Column.EditTriggersProperty, value );
      }
    }

    private static void OnEditTriggersChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.EditTriggers );
    }

    #endregion // EditTriggers Property

    #region CellHorizontalContentAlignment Property

    public static readonly DependencyProperty CellHorizontalContentAlignmentProperty = DependencyProperty.Register(
      "CellHorizontalContentAlignment",
      typeof( HorizontalAlignment? ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnCellHorizontalContentAlignmentChanged ) ) );

    public HorizontalAlignment? CellHorizontalContentAlignment
    {
      get
      {
        return ( HorizontalAlignment? )this.GetValue( Column.CellHorizontalContentAlignmentProperty );
      }
      set
      {
        this.SetValue( Column.CellHorizontalContentAlignmentProperty, value );
      }
    }

    private static void OnCellHorizontalContentAlignmentChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellHorizontalContentAlignment );
    }

    #endregion // CellHorizontalContentAlignment Property

    #region CellVerticalContentAlignment Property

    public static readonly DependencyProperty CellVerticalContentAlignmentProperty = DependencyProperty.Register(
      "CellVerticalContentAlignment",
      typeof( VerticalAlignment? ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnCellVerticalContentAlignmentChanged ) ) );

    public VerticalAlignment? CellVerticalContentAlignment
    {
      get
      {
        return ( VerticalAlignment? )this.GetValue( Column.CellVerticalContentAlignmentProperty );
      }
      set
      {
        this.SetValue( Column.CellVerticalContentAlignmentProperty, value );
      }
    }

    private static void OnCellVerticalContentAlignmentChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellVerticalContentAlignment );
    }

    #endregion CellVerticalContentAlignment Property

    #region CellStyle Property

    public static readonly DependencyProperty CellStyleProperty = DependencyProperty.Register(
      "CellStyle",
      typeof( Style ),
      typeof( Column ),
      new PropertyMetadata( null, Column.OnCellStyleChanged ) );

    public Style CellStyle
    {
      get
      {
        return ( Style )this.GetValue( Column.CellStyleProperty );
      }
      set
      {
        this.SetValue( Column.CellStyleProperty, value );
      }
    }

    private static void OnCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellStyle );
    }

    #endregion // CellStyle Property

    #region ColumnManagerCellStyle Property

    public static readonly DependencyProperty ColumnManagerCellStyleProperty = DependencyProperty.Register(
      "ColumnManagerCellStyle",
      typeof( Style ),
      typeof( Column ),
      new PropertyMetadata( null, Column.OnColumnManagerCellStyleChanged ) );

    public Style ColumnManagerCellStyle
    {
      get
      {
        return ( Style )this.GetValue( Column.ColumnManagerCellStyleProperty );
      }
      set
      {
        this.SetValue( Column.ColumnManagerCellStyleProperty, value );
      }
    }

    private static void OnColumnManagerCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.ColumnManagerCellStyle );
    }

    #endregion // ColumnManagerCellStyle Property

    #region FilterCellStyle Property

    public static readonly DependencyProperty FilterCellStyleProperty = DependencyProperty.Register(
      "FilterCellStyle",
      typeof( Style ),
      typeof( Column ),
      new PropertyMetadata( null, Column.OnFilterCellStyleChanged ) );

    public Style FilterCellStyle
    {
      get
      {
        return ( Style )this.GetValue( Column.FilterCellStyleProperty );
      }
      set
      {
        this.SetValue( Column.FilterCellStyleProperty, value );
      }
    }

    private static void OnFilterCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.FilterCellStyle );
    }

    #endregion // FilterCellStyle Property

    #region InsertionCellStyle Property

    public static readonly DependencyProperty InsertionCellStyleProperty = DependencyProperty.Register(
      "InsertionCellStyle",
      typeof( Style ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnInsertionCellStyleChanged ) ) );

    public Style InsertionCellStyle
    {
      get
      {
        return ( Style )this.GetValue( Column.InsertionCellStyleProperty );
      }
      set
      {
        this.SetValue( Column.InsertionCellStyleProperty, value );
      }
    }

    private static void OnInsertionCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.InsertionCellStyle );
    }

    #endregion // InsertionCellStyle Property

    #region DisplayMemberBindingInfo Property

    public DataGridBindingInfo DisplayMemberBindingInfo
    {
      get
      {
        return m_displayMemberBindingInfo;
      }
      set
      {
        if( value == null )
          throw new ArgumentNullException( "DisplayMemberBindingInfo" );

        if( value == m_displayMemberBindingInfo )
          return;

        DataGridBindingInfo oldValue = m_displayMemberBindingInfo;
        m_displayMemberBindingInfo = value;
        m_displayMemberBinding = m_displayMemberBindingInfo.GetBinding();

        this.DisplayDataType = null;

        if( this.SortBindingInfo == null )
        {
          this.RaiseValuesPropertyChanged(
            () => this.SortFieldName,
            this.ResolveSortFieldName( oldValue, null ),
            this.ResolveSortFieldName( m_displayMemberBindingInfo, null ) );
        }

        this.RaisePropertyChanged( () => this.DisplayMemberBindingInfo );
      }
    }

    private DataGridBindingInfo m_displayMemberBindingInfo; //null

    #endregion

    #region DisplayMemberBinding Property

    internal Binding DisplayMemberBinding
    {
      get
      {
        return m_displayMemberBinding;
      }
    }

    private Binding m_displayMemberBinding; //null

    #endregion //DisplayMemberBinding Property

    #region DisplayTitle Property (Internal)

    internal object DisplayTitle
    {
      get
      {
        return ( this.Title != null ) ? this.Title : this.FieldName;
      }
    }

    #endregion

    #region DisplayDataType Property (Internal)

    internal Type DisplayDataType
    {
      get
      {
        return m_displayDataType;
      }
      set
      {
        if( value == m_displayDataType )
          return;

        m_displayDataType = value;

        this.RaisePropertyChanged( () => this.DisplayDataType );
      }
    }

    private Type m_displayDataType;

    #endregion

    #region FieldName Property

    public string FieldName
    {
      get
      {
        return m_fieldName;
      }
      set
      {
        if( value != m_fieldName )
        {
          string oldFieldName = m_fieldName;
          m_fieldName = value;

          if( ( ( this.DisplayMemberBindingInfo == null ) || ( this.DisplayMemberBindingInfo.IsAutoGenerated ) )
           && ( !String.IsNullOrEmpty( m_fieldName ) ) )
          {
            this.DisplayMemberBindingInfo = new DataGridBindingInfo( m_fieldName, true, true );
          }

          this.RaiseDisplayTitleChanged();
        }
      }
    }

    private string m_fieldName;

    #endregion

    #region GroupDescription Property

    public static readonly DependencyProperty GroupDescriptionProperty = DependencyProperty.Register(
      "GroupDescription",
      typeof( GroupDescription ),
      typeof( Column ),
      new PropertyMetadata( null ) );

    public GroupDescription GroupDescription
    {
      get
      {
        return ( GroupDescription )this.GetValue( Column.GroupDescriptionProperty );
      }
      set
      {
        this.SetValue( Column.GroupDescriptionProperty, value );
      }
    }

    #endregion

    #region MinWidth Property

    // Not a DP to allow a well-implemented validation.
    public double? MinWidth
    {
      get
      {
        return m_minWidth;
      }
      set
      {
        if( value.HasValue )
        {
          if( value.Value < 0d )
            throw new ArgumentOutOfRangeException( "MinWidth", "MinWidth must be greater than or equal to zero." );

          if( Double.IsPositiveInfinity( value.Value ) )
            throw new ArgumentOutOfRangeException( "MinWidth", "MinWidth must be less than positive infinity." );
        }

        m_minWidth = value;

        this.RaisePropertyChanged( () => this.MinWidth );
      }
    }

    private double? m_minWidth; // null

    #endregion //MinWidth Property

    #region MaxWidth Property

    // Not a DP to allow a well-implemented validation.
    public double? MaxWidth
    {
      get
      {
        return m_maxWidth;
      }
      set
      {
        if( value.HasValue )
        {
          if( value.Value < 0d )
            throw new ArgumentOutOfRangeException( "MaxWidth", "MaxWidth must be greater than or equal to zero." );
        }

        m_maxWidth = value;

        this.RaisePropertyChanged( () => this.MaxWidth );
      }
    }

    private double? m_maxWidth; // null

    #endregion //MaxWidth Property

    #region ReadOnly Property

    public static readonly DependencyProperty ReadOnlyProperty = DependencyProperty.Register(
      "ReadOnly",
      typeof( Nullable<bool> ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnReadOnlyChanged ) ) );

    public Nullable<bool> ReadOnly
    {
      get
      {
        return ( Nullable<bool> )this.GetValue( Column.ReadOnlyProperty );
      }
      set
      {
        this.SetValue( Column.ReadOnlyProperty, value );
      }
    }

    private static void OnReadOnlyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.ReadOnly );
    }

    #endregion // ReadOnly Property

    #region SortBindingInfo Property

    public static readonly DependencyProperty SortBindingInfoProperty = DependencyProperty.Register(
      "SortBindingInfo",
      typeof( string ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnSortBindingInfoChanged ) ) );

    public string SortBindingInfo
    {
      get
      {
        return ( string )this.GetValue( Column.SortBindingInfoProperty );
      }
      set
      {
        this.SetValue( Column.SortBindingInfoProperty, value );
      }
    }

    private static void OnSortBindingInfoChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaiseValuesPropertyChanged(
        () => column.SortFieldName,
        column.ResolveSortFieldName( column.DisplayMemberBindingInfo, ( string )e.OldValue ),
        column.ResolveSortFieldName( column.DisplayMemberBindingInfo, ( string )e.NewValue ) );
    }

    #endregion

    #region SortDirection Property

    public static readonly DependencyProperty SortDirectionProperty = DependencyProperty.Register(
      "SortDirection",
      typeof( SortDirection ),
      typeof( Column ),
      new PropertyMetadata( ( SortDirection )SortDirection.None, new PropertyChangedCallback( Column.OnSortDirectionChanged ) ) );

    public SortDirection SortDirection
    {
      get
      {
        return ( SortDirection )this.GetValue( Column.SortDirectionProperty );
      }
      set
      {
        this.SetValue( Column.SortDirectionProperty, value );
      }
    }

    private static void OnSortDirectionChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.SortDirection );
    }

    #endregion

    #region SortFieldName

    internal string SortFieldName
    {
      get
      {
        return this.ResolveSortFieldName( this.DisplayMemberBindingInfo, this.SortBindingInfo );
      }
    }

    #endregion

    #region Title Property

    public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
      "Title",
      typeof( object ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnTitleChanged ) ) );

    public object Title
    {
      get
      {
        return ( object )this.GetValue( Column.TitleProperty );
      }
      set
      {
        this.SetValue( Column.TitleProperty, value );
      }
    }

    private static void OnTitleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = sender as Column;
      column.RaiseDisplayTitleChanged();
    }

    #endregion // Title Property

    #region TitleTemplate Property

    public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register(
      "TitleTemplate",
      typeof( DataTemplate ),
      typeof( Column ),
      new PropertyMetadata(
        null,
        new PropertyChangedCallback( Column.OnTitleTemplateChanged ) ) );

    public DataTemplate TitleTemplate
    {
      get
      {
        return ( DataTemplate )this.GetValue( Column.TitleTemplateProperty );
      }
      set
      {
        this.SetValue( Column.TitleTemplateProperty, value );
      }
    }

    private static void OnTitleTemplateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.TitleTemplate );
    }

    #endregion //TitleTemplate Property

    #region CellEditorTemplate Property

    public static readonly DependencyProperty CellEditorTemplateProperty = DependencyProperty.Register(
      "CellEditorTemplate",
      typeof( DataTemplate ),
      typeof( Column ),
      new PropertyMetadata( null, new PropertyChangedCallback( Column.OnCellEditorTemplateChanged ) ) );

    public DataTemplate CellEditorTemplate
    {
      get
      {
        return ( DataTemplate )this.GetValue( Column.CellEditorTemplateProperty );
      }
      set
      {
        this.SetValue( Column.CellEditorTemplateProperty, value );
      }
    }

    private static void OnCellEditorTemplateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellEditorTemplate );
    }

    #endregion

    #region CellEditorStyle Property

    public static readonly DependencyProperty CellEditorStyleProperty = DependencyProperty.Register(
      "CellEditorStyle",
      typeof( Style ),
      typeof( Column ),
      new PropertyMetadata( null, Column.OnCellEditorStyleChanged ) );

    public Style CellEditorStyle
    {
      get
      {
        return ( Style )this.GetValue( Column.CellEditorStyleProperty );
      }
      set
      {
        this.SetValue( Column.CellEditorStyleProperty, value );
      }
    }

    private static void OnCellEditorStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.CellEditorStyle );
    }

    #endregion

    #region IsAutoGenerated Property (Internal)

    internal bool IsAutoGenerated
    {
      get;
      set;
    }

    #endregion

    #region Visible Property

    public static readonly DependencyProperty VisibleProperty = DependencyProperty.Register(
      "Visible",
      typeof( bool ),
      typeof( Column ),
      new PropertyMetadata(
        true,
        new PropertyChangedCallback( Column.OnVisibleChanged ) ) );

    public bool Visible
    {
      get
      {
        return ( bool )this.GetValue( Column.VisibleProperty );
      }
      set
      {
        this.SetValue( Column.VisibleProperty, value );
      }
    }

    private static void OnVisibleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.Visible );
    }

    #endregion

    #region VisiblePosition Property

    public static readonly DependencyProperty VisiblePositionProperty = DependencyProperty.Register(
      "VisiblePosition",
      typeof( int ),
      typeof( Column ),
      new PropertyMetadata( -1, new PropertyChangedCallback( Column.OnVisiblePositionChanged ) ) );

    public int VisiblePosition
    {
      get
      {
        return ( int )this.GetValue( Column.VisiblePositionProperty );
      }
      set
      {
        this.SetValue( Column.VisiblePositionProperty, value );
      }
    }

    private static void OnVisiblePositionChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaiseValuesPropertyChanged( () => column.VisiblePosition, ( int )e.OldValue, ( int )e.NewValue );
    }

    #endregion //VisiblePosition Property

    #region Width Property

    public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
      "Width",
      typeof( double ),
      typeof( Column ),
      new PropertyMetadata( Column.DefaultWidth, new PropertyChangedCallback( Column.OnWidthChanged ) ) );

    public double Width
    {
      get
      {
        return ( double )this.GetValue( Column.WidthProperty );
      }
      set
      {
        this.SetValue( Column.WidthProperty, value );
      }
    }

    private static void OnWidthChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Column column = ( Column )sender;
      column.RaisePropertyChanged( () => column.Width );
    }

    #endregion // Width Property

    #region TextTrimming Property

    public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
      "TextTrimming",
      typeof( TextTrimming ),
      typeof( Column ),
      new PropertyMetadata( TextTrimming.WordEllipsis, new PropertyChangedCallback( Column.OnTextTrimmingPropertyChanged ) ) );

    public TextTrimming TextTrimming
    {
      get
      {
        return ( TextTrimming )this.GetValue( Column.TextTrimmingProperty );
      }
      set
      {
        this.SetValue( Column.TextTrimmingProperty, value );
      }
    }

    private static void OnTextTrimmingPropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var column = ( Column )sender;
      column.RaisePropertyChanged( () => column.TextTrimming );
    }

    #endregion

    #region ActivatingCellEditor Event

    public event EventHandler<ActivatingCellEditorEventArgs> ActivatingCellEditor;

    internal void OnActivatingCellEditor( Cell targetCell, FrameworkElement editor )
    {
      if( targetCell == null )
        throw new ArgumentNullException( "targetCell" );

      if( editor == null )
        throw new ArgumentNullException( "editor" );

      if( targetCell.ParentColumn != this )
        throw new ArgumentException( "The cell must be part of the column.", "targetCell" );

      if( this.ActivatingCellEditor != null )
      {
        this.ActivatingCellEditor( this, new ActivatingCellEditorEventArgs( targetCell, editor ) );
      }
    }

    #endregion


    internal bool GetEffectiveAllowFilter()
    {
      return this.AllowFilter;
    }

    internal string GetSortFieldName()
    {
      return ( this.SortBindingInfo != null ) ?
        this.SortBindingInfo :
        this.DisplayMemberBinding.Path.Path;
    }

    private void RaiseDisplayTitleChanged()
    {
      this.RaisePropertyChanged( () => this.DisplayTitle );
    }

    private string ResolveSortFieldName( DataGridBindingInfo bindingInfo, string sortBindingInfo )
    {
      if( sortBindingInfo != null )
        return sortBindingInfo;

      if( bindingInfo == null )
        return null;

      return bindingInfo.Path.Path;
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged( string propertyName )
    {
      m_propertyChangedHelper.RaisePropertyChanged( propertyName );
    }

    protected void RaisePropertyChanged<TMember>( Expression<Func<TMember>> expression )
    {
      if( m_propertyChangedHelper != null )
      {
        m_propertyChangedHelper.RaisePropertyChanged( expression );
      }
    }

    private void RaisePropertyChangedEvent( string propertyName )
    {
      if( this.PropertyChanged != null )
      {
        this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
      }
    }

    private void RaiseValuesPropertyChanged<TMember>( Expression<Func<TMember>> expression, object oldValue, object newValue )
    {
      if( PropertyChanged != null )
      {
        var propertyName = NotifyPropertyChangedHelper.GetPropertyName( expression, typeof( Column ) );
        this.PropertyChanged( this, new ValuesPropertyChangedEventArgs( propertyName, oldValue, newValue ) );
      }
    }

    private readonly NotifyPropertyChangedHelper m_propertyChangedHelper;

    #endregion
  }
}
